%%--------------------------------------------------------------------
%% Author: <vjache>
%% Created: 17.03.2009
%% Description: TODO: Add description to merge_sort
%%--------------------------------------------------------------------
-module(iter_join_cprod).

%%--------------------------------------------------------------------
%% Include files
%%--------------------------------------------------------------------
-include_lib("eunit/include/eunit.hrl").

-include("../include/iter.hrl").
%%--------------------------------------------------------------------
%% Exported Functions
%%--------------------------------------------------------------------
-export([
		 new/2,
		 new/3,
		 open/1,
		 next/1,
		 close/1,
		 all/1,
		 row_flatten/1
		 ]).

%%--------------------------------------------------------------------
%% API Functions
%%--------------------------------------------------------------------

open({Iter1,Iter2,FilterPredFun}) ->
	State1=iter:open(Iter1),
	{NewSate1,CurrItem1}=iter:next(State1),
	{NewSate1,{Iter2,need_open},FilterPredFun,CurrItem1}.

next({_State1,_State2,_FilterPredFun,?EOF}=S) ->
	{S,?EOF};
next({State1,{Iter2,need_open},FilterPredFun,CurrItem1}=_S) ->
	State2=iter:open(Iter2),
	next({State1,State2,FilterPredFun,CurrItem1});
next({State1,{Iter2,_}=State2,FilterPredFun,CurrItem1}=_S) ->
	{NewState2,Item2}=iter:next(State2),
	case Item2 of
		?EOF ->
			ok=iter:close(NewState2),
			{NewState1,Item1}=iter:next(State1),
			next({NewState1,{Iter2,need_open},FilterPredFun,Item1});
		_ ->
			case FilterPredFun(CurrItem1,Item2) of
				true ->
					{{State1,NewState2,FilterPredFun,CurrItem1},{'$cprod',CurrItem1,Item2}};
				false ->
					next({State1,NewState2,FilterPredFun,CurrItem1})
			end
	end.


close({State1,{_Iter2,need_open}=_State2,_FilterPredFun,_CurrItem1}) ->
	ok=iter:close(State1);
close({State1,State2,_FilterPredFun,_CurrItem1}) ->
	ok=iter:close(State1),
	ok=iter:close(State2).

new(Iter1,Iter2,FilterPredFun) ->
	iter:from_module(?MODULE, { Iter1,Iter2,FilterPredFun }).

new(Iter1,Iter2) ->
	new(Iter1,
		Iter2,
		fun(_It1,_It2)->
			true
		end).

all([]=_IterList) ->
	iter:empty();
all([Iter1|RestIters]=_IterList) ->
	lists:foldl(
		fun(Iter,AccIn)->
			new(AccIn,Iter)
		end, Iter1, RestIters).

row_flatten({'$cprod',_Left,_Right}=Arg) ->
	do_flatten(Arg,[]);
row_flatten(Arg) ->
	[Arg].

do_flatten({'$cprod',Left,Right},Tail) ->
	do_flatten(Left,do_flatten(Right,Tail));
do_flatten(Elem,Tail) ->
	[Elem|Tail].

	

%%--------------------------------------------------------------------
%% eunit test functions
%%--------------------------------------------------------------------
basic_test() ->
	TestData1=[1,2,3],
	TestData2=[a,b,c],
	I=new(iter:from_list(TestData1),iter:from_list(TestData2)),
	iter:print(I).
%%--------------------------------------------------------------------
%% Local Functions
%%--------------------------------------------------------------------
